package com.sunbim.rsrv.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.img.Img;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sunbim.rsrv.common.exception.RequestException;
import com.sunbim.rsrv.common.exception.ServiceException;
import com.sunbim.rsrv.mapper.StorageMapper;
import com.sunbim.rsrv.pojo.Storage;
import com.sunbim.rsrv.service.StorageService;
import com.sunbim.rsrv.vo.storage.StorageVo;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author yuhui
 * @since 2021-12-30
 */
@Slf4j
@Service
public class StorageServiceImpl extends ServiceImpl<StorageMapper, Storage> implements StorageService {

    @Autowired
    StorageMapper storageMapper;

    private final String staticPathRoot = System.getProperty("user.dir") + File.separator + "static";

    @Value("${staticServer.uri}")
    private String yamlUri;


    @SneakyThrows
    @Transactional
    @Override
    public StorageVo upload(Integer parentId, Integer userId, Integer relicsId, String type, String desc, MultipartFile file) {
        if (file == null) throw new RequestException("请选择要上传的文件");

        String tail;
        String fileType = file.getContentType();
        if (ObjectUtil.isNull(fileType)) throw new RequestException("不支持的文件类型");
        switch (fileType) {
            case "image/png":
            case "image/jpeg":
                tail = ".jpg";
                break;
            case "application/pdf":
                tail = ".pdf";
                break;
            default:
                throw new RequestException("不支持的文件类型");
        }
        // 重命名文件
        String storageName = IdUtil.simpleUUID() + tail;

        // 生成存储路径
        String storagePath = staticPathRoot + File.separator + storageName;

        // 生成url
        String uri = StrUtil.removeSuffix(yamlUri, "**");
        String url = URLUtil.normalize(uri + storageName, true, true);
        String storageUrl = StrUtil.removePrefix(url, "http:/");

        // 先更新数据库,后保存图片,若保存图片失败,则通过事务回滚
        Storage storage = new Storage();
        storage.setParentId(parentId);
        storage.setUserId(userId);
        storage.setRelicsId(relicsId);
        storage.setStorageType(type);
        storage.setStorageDesc(desc);

        storage.setStorageName(storageName);
        storage.setStoragePath(storagePath);
        storage.setStorageUrl(storageUrl);

        storageMapper.insert(storage);

        // 创建文件对象
        File dest = new File(storagePath);
        // 如果目录不存在则创建目录
        if (!dest.getParentFile().exists()) {
            boolean isMkdirs = dest.getParentFile().mkdirs();
            if (!isMkdirs) throw new ServiceException("文件保存失败,创建目录失败");
        }
        if (tail.equals(".jpg")) {
            // 压缩并保存图片
            Img.from(file.getInputStream()).setQuality(0.8).write(dest);
        } else {
            file.transferTo(dest);
        }
        // 构造返回数据
        StorageVo storageVo = new StorageVo();
        BeanUtil.copyProperties(storage, storageVo);
        return storageVo;
    }

    @SneakyThrows
    @Transactional
    @Override
    public StorageVo update(Integer id, Integer userId, Integer relicsId, String type, String desc, MultipartFile file) {
        if (file == null) throw new RequestException("请选择要上传的图片");
        String tail;
        String fileType = file.getContentType();
        if (ObjectUtil.isNull(fileType)) throw new RequestException("不支持的文件类型");
        switch (fileType) {
            case "image/png":
            case "image/jpeg":
                tail = ".jpg";
                break;
            case "application/pdf":
                tail = ".pdf";
                break;
            default:
                throw new RequestException("不支持的文件类型");
        }
        // 重命名文件
        String storageName = IdUtil.simpleUUID() + tail;

        // 生成存储路径
        String storagePath = staticPathRoot + File.separator + storageName;

        // 生成url
        String uri = StrUtil.removeSuffix(yamlUri, "**");
        String url = URLUtil.normalize(uri + storageName, true, true);
        String storageUrl = StrUtil.removePrefix(url, "http:/");

        // 先更新数据库,后保存图片,若保存图片失败,则通过事务回滚
        Storage storage = new Storage();
        storage.setId(id);
        storage.setUserId(userId);
        storage.setRelicsId(relicsId);
        storage.setStorageType(type);
        storage.setStorageDesc(desc);
        storage.setStorageName(storageName);
        storage.setStoragePath(storagePath);
        storage.setStorageUrl(storageUrl);

        storageMapper.updateById(storage);
        // 创建文件对象
        File dest = new File(storagePath);
        // 如果目录不存在则创建目录
        if (!dest.getParentFile().exists()) {
            boolean isMkdirs = dest.getParentFile().mkdirs();
            if (!isMkdirs) throw new ServiceException("文件保存失败,创建目录失败");
        }
        if (tail.equals(".jpg")) {
            // 压缩并保存图片
            Img.from(file.getInputStream()).setQuality(0.8).write(dest);
        } else {
            file.transferTo(dest);
        }

        // 构造返回数据
        StorageVo storageVo = new StorageVo();
        BeanUtil.copyProperties(storage, storageVo);
        return storageVo;
    }

    @Transactional
    @Override
    public String delete(int id) {
        storageMapper.deleteById(id);
        QueryWrapper<Storage> storageQueryWrapper = new QueryWrapper<>();
        storageQueryWrapper.eq("parent_id", id);
        storageMapper.delete(storageQueryWrapper);
        return "删除成功";
    }


    @Override
    public void deleteAllByUserId(int userId) {
        QueryWrapper<Storage> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        storageMapper.delete(wrapper);
    }

    @Override
    public void deleteAllByRelicsId(int relicsId) {
        QueryWrapper<Storage> wrapper = new QueryWrapper<>();
        wrapper.eq("relics_id", relicsId);
        storageMapper.delete(wrapper);
    }

    @Override
    public List<StorageVo> getListByRelicsIdAndType(int relicsId, String type) {

        return storageMapper.selectByRelicsIdAndType(relicsId, type);
    }

    @Override
    public boolean idExit(Integer id) {
        return storageMapper.idExit(id);
    }

    @Override
    public List<Map<String, Object>> getReports(Integer relicsId) {
        return storageMapper.getReports(relicsId);
    }

    @Override
    public void deleteBatch(List<Integer> ids) {
        storageMapper.deleteBatchIds(ids);
    }

    @Transactional
    @SneakyThrows
    @Override
    public void uploadReport(Integer relicsId, MultipartFile report) {
        // 重命名文件
        String storageName = IdUtil.simpleUUID() + ".pdf";
        // 生成存储路径
        String storagePath = staticPathRoot + File.separator + storageName;
        // 生成url
        String uri = StrUtil.removeSuffix(yamlUri, "**");
        String url = URLUtil.normalize(uri + storageName, true, true);
        String storageUrl = StrUtil.removePrefix(url, "http:/");

        // 先更新数据库,后保存图片,若保存图片失败,则通过事务回滚
        Storage storage = new Storage();
        storage.setRelicsId(relicsId);
        storage.setStorageType("report");
        storage.setStorageName(storageName);
        storage.setStoragePath(storagePath);
        storage.setStorageUrl(storageUrl);
        storageMapper.insert(storage);
        // 创建文件对象
        File dest = new File(storagePath);
        // 如果目录不存在则创建目录
        if (!dest.getParentFile().exists()) {
            boolean isMkdirs = dest.getParentFile().mkdirs();
            if (!isMkdirs) throw new ServiceException("文件保存失败,创建目录失败");
        }
        // 保存文件
        report.transferTo(dest);

        // 读取pdf的第一页 作为封面图片 保存
        PDDocument document = PDDocument.load(dest);
        PDFRenderer renderer = new PDFRenderer(document);
        BufferedImage bufferedImage = renderer.renderImage(0);
        //将newImage写入字节数组输出流
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(bufferedImage, "jpg", baos);
        MultipartFile reportCover = new MockMultipartFile("temp.jpg", "temp.jpg", "image/jpeg", baos.toByteArray());
        upload(storage.getId(), null, relicsId, "report_cover", "", reportCover);
    }

    @Override
    public StorageVo getEva() {
        QueryWrapper<Storage> wrapper = new QueryWrapper<>();
        wrapper.eq("storage_type", "eva_method");
        Storage storage = storageMapper.selectOne(wrapper);
        StorageVo storageVo = new StorageVo();
        BeanUtil.copyProperties(storage, storageVo);
        return storageVo;
    }
}
